package client

import (
	"context"
	"github.com/eyotang/boomer"
	"github.com/valyala/fasthttp"
	"httpTemplate/stats"

	"net"
)

type CheckFunc func(ctx boomer.Context, statusCode int, body []byte) error

var HostIPMap = make(map[string]string)

type Client struct {
	request *Request
	fc      *fasthttp.Client
	buff    []byte
}

func NewClient() *Client {
	dialer := &net.Dialer{
		//Timeout:   30 * time.Second,
		//KeepAlive: 30 * time.Second,
		//DualStack: true,
	}

	return &Client{fc: &fasthttp.Client{
		MaxConnsPerHost: 8000,
		DialDualStack:   true,
		Dial: func(addr string) (net.Conn, error) {
			if ip, ok := HostIPMap[addr]; ok {
				addr = ip
			}
			return dialer.DialContext(context.Background(), "tcp", addr)
		},
	}}
}

func (c *Client) NewRequest(ctx boomer.Context, name string, cf CheckFunc) *Request {
	return NewRequest(c, ctx, name, cf)
}

func (c *Client) Do(req *Request) *Request {
	var (
		err        error
		statusCode int
		body       []byte
		name       = req.name
	)

	start := boomer.Now()
	statusCode, body, err = c.doNow(req)
	duration := boomer.Now() - start
	if err != nil {
		req.AddError(err)
		stats.RecordFailure("http", name, duration, req.Error.Error())
		return req
	}

	if req.cf != nil {
		if err = req.cf(req.ctx, statusCode, body); err != nil {
			req.AddError(err)
			stats.RecordFailure("http", name, duration, req.Error.Error())
			return req
		}
	}

	stats.RecordSuccess("http", name, duration, int64(len(body)))
	return req

}

func GetCookie(rsp *fasthttp.Response, cookieKey string) string {
	cookie := fasthttp.AcquireCookie()
	cookie.SetKey(cookieKey)
	rsp.Header.Cookie(cookie)
	return string(cookie.Value())
}

func (c *Client) doNow(req *Request) (statusCode int, body []byte, err error) {
	rsp := fasthttp.AcquireResponse()
	old := rsp.SwapBody(c.buff)
	err = c.fc.Do(req.request, rsp)

	statusCode = rsp.StatusCode()

	body = rsp.Body()
	c.buff = rsp.SwapBody(old)

	fasthttp.ReleaseResponse(rsp)
	return
}
